package kamkor.ann.namerecog.network

import kamkor.ann.namerecog.network.trainer._
import kamkor.ann.namerecog.network.converter._

import org.encog.neural.data.basic.BasicNeuralDataSet
import org.encog.neural.data.basic.BasicNeuralData
import org.encog.neural.networks.layers.BasicLayer

/** Adapts low-level network to a higher level. It accepts input which is human readable - in 
 *  string format and converts it to format understandable by low-level ann
 * 
 *  Also contains easy to use training method, which has useful callback method
 * 
 * @author kamkor
 *
 */
class NetworkAdapter(inputConverter: InputConverter, outputConverter: OutputConverter, inputLength: Int, hiddenLength: Int, outputLength: Int) {	
	val layers = 
		List(
				new BasicLayer(inputLength),
				new BasicLayer(hiddenLength),
				new BasicLayer(outputLength)				
		)		
	val network = new FeedforwardResilient(layers)
	
	def compute(surname: String) {
		val convInput = inputConverter.convert(surname, inputLength)
		val convOutput = outputConverter.convert(network.compute(new BasicNeuralData(convInput)))
	}
	
	/**
	 * Trains neural network until all epochs have passed or until maxError was reached 
	 * 
	 * @param trainingData
	 * @param epochs
	 * @param maxError
	 * @param doAfterIter is called after each iteration
	 */
	def train(data: BasicNeuralDataSet, epochs: Int, maxError: Double, doAfterIter: (Int, Double) => Unit) {
		network.setTraining(data)
		
		var epoch = 0
		do {
			network.train()			
			doAfterIter(epoch, network.getError())
			epoch += 1
		} while (epoch < epochs && network.getError() > maxError)	
	}
	
}